/*
 * Copyright 2008. Mount Sinai Hospital, Toronto, Canada.
 * 
 * Licensed under the Apache License, Version 2.0. You
 * can find a copy of the license at:
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * IN NO EVENT SHALL MOUNT SINAI HOSPITAL BE LIABLE TO ANY PARTY FOR DIRECT, 
 * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST 
 * PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, 
 * EVEN IF MOUNT SINAI HOSPITAL HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 
 * DAMAGE.
 * 
 * MOUNT SINAI HOSPITAL SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF 
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE AND 
 * ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". 
 * MOUNT SINAI HOSPITAL HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, 
 * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 
 */

package com.sinai.mshab.extensions.search;

import java.util.ArrayList;

import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.ClickListener;
import com.google.gwt.user.client.ui.DisclosurePanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
import com.sinai.mshab.format.Direction;
import com.sinai.mshab.format.FormatPanel;
import com.sinai.mshab.format.util.Observable;
import com.sinai.mshab.format.util.Observer;
import com.sinai.mshab.widgets.ExpandableTable;

/**
 * Creates an advanced search filter table.
 * 
 * @author serge
 * 
 */
public class AdvancedSearch extends VerticalPanel implements Observable {

	private ExpandableTable categories;
	private AdvancedSearchParser parser;
	private ResultsGrid grid;
	private String keyField;
	private ArrayList<Observer> observers = new ArrayList<Observer>();
	private ArrayList<Observer> resultObservers = new ArrayList<Observer>();

	public AdvancedSearch(DatabaseStructure structure, String keyField) {

		// save the key field (id) which will trigger records
		this.keyField = keyField;

		// instructions
		Label instructions = new Label(
				"On this page you can provide filtering criteria to"
						+ " make custom reports. Select the category by which"
						+ " you want to sort by clicking the 'Add a Category' "
						+ "button. You can add several criteria per Category by"
						+ " clicking 'Add Filter Crtiteria'. When you are done, "
						+ "click on the 'Run Report' button so see the report.");
		instructions.setStyleName("mshab-DescrptionLabel");
		add(instructions);

		// adding category table.
		categories = new ExpandableTable("Add another category");
		categories.includeRemoveLinks();
		categories.add(new SearchCategory(structure));
		add(categories);

		// adding query details
		FormatPanel details = new FormatPanel();
		details.setStyleName("mshab-SearchDetails");
		details.setDefaultLabelPosition(Direction.LEFT);
		details.setDefaultLeftLabelWidth(150);

		// sort by widget
		SortByWidget sortBy = SortByWidget.getInstance();
		details.add(sortBy);
		details.setLabel(sortBy, "Sort By:");

		// sort order options
		ListBox sortOrder = new ListBox();
		sortOrder.addItem("Ascending");
		sortOrder.addItem("Descending");
		details.add(sortOrder);
		details.setLabel(sortOrder, "Sort Order");

		// show records options
		ListBox showRecords = new ListBox();
		showRecords.addItem("5");
		showRecords.addItem("10");
		showRecords.addItem("25");
		showRecords.addItem("50");
		showRecords.addItem("100");
		showRecords.setSelectedIndex(3);
//		details.add(showRecords);
//		details.setLabel(showRecords, "Show Records");

		// adding the details
		DisclosurePanel disclose_details = new DisclosurePanel(
				"Show Ordering details");
		disclose_details.add(details);
		disclose_details.setAnimationEnabled(true);
		add(disclose_details);

		// Run the report button
		Button run = new Button("Search");
		run.addClickListener(new RunReportListner());
		add(run);
	}

	public void setUpGrid() {

		// remove any old grids
		if (grid != null) {
			remove(grid);
		}

		//TODO: fix later.
		// recreate the grid.
//		grid = new ResultsGrid(parser.getColumns());
		grid = new ResultsGrid();

		// tell the grid who to report to for click events
		for (int i = 0; i < resultObservers.size(); i++) {
			grid.addObserver(resultObservers.get(i));
		}

		// add the grid
		add(grid);
	}

	/**
	 * This returns all the created category objects that we have.
	 * 
	 * @return
	 */
	public ArrayList<SearchCategory> getCategories() {
		ArrayList<SearchCategory> category_list = new ArrayList<SearchCategory>();

		// go through all our rows and throw categories into the arraylist.
		int rows = categories.getRowCount();
		for (int i = 1; i < rows - 1; i++) {
			category_list.add((SearchCategory) categories.getWidget(i, 0));
		}

		return category_list;
	}

	/**
	 * instruct the advanced search parser to parse the user selection.
	 */
	private void parse() {
		parser = new AdvancedSearchParser();
		parser.parse(this);
	}

	/**
	 * This listens to the run report button.
	 * 
	 * @author serge
	 * 
	 */
	private class RunReportListner implements ClickListener {

		public void onClick(Widget sender) {
			parse();
			setUpGrid();
		}
	}

	/**
	 * Returns the key field.
	 * 
	 * @return
	 */
	public String getKeyField() {
		return keyField;
	}

	public void addObserver(Observer o) {
		observers.add(o);
	}

	/**
	 * Advanced search will buffer result observers and feed them into the grid
	 * upon it's creation
	 */
	public void addResultsObserver(Observer o) {
		resultObservers.add(o);
	}

	public void notifyObservers() {
		for (int i = 0; i < observers.size(); i++) {
			observers.get(i).update(this, "search requested");
		}
	}

	public int countObservers() {
		return observers.size();
	}

	public void deleteObserver(Observer observer) {
		observers.remove(observer);
	}

	public void deleteObservers() {
		observers.clear();
	}
}
